﻿using System;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.Security.Permissions;



namespace WinRun
{

    public partial class FormMain : Form
    {

        #region Vars and Consts

        /** used to keep track commands that have been type for this session **/
        private AutoCompleteStringCollection commandHistory = new AutoCompleteStringCollection();


        private string filePath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\aliases.xml";

        /** keeps track of where we're at in the command history **/
        int currentIndex;

        /** object to handle setting/removing hotkey with system **/
        KeyboardHook kbh = new KeyboardHook();


        /** Posted when LMouse button pressed **/
        private const int WM_NCLBUTTONDOWN = 0xA1;
        private const int HTCAPTION = 0x2;

        /** For checking registered hotkeys **/
        private const int WM_HOTKEY = 0x0312;
        private const int WM_SHOW = 0x018;

        #endregion

        #region Constructor and Form Methods

        /// <summary>
        /// Constructor
        /// </summary>
        public FormMain()
        {
            InitializeComponent();
            kbh.RegisterGlobalHotKey((int)Keys.D, (int)KeyboardHook.ModifierKeycodes.MOD_ALT, this.Handle);
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            RefreshTheme();

            /** make sure theres an alias.xml file **/
            if (!File.Exists(filePath))
            {
                /** no? create one **/
                var a = new Alias();
                a.CreateNewAliasFile();
                a = null;

            }

            TxtCommand.Focus();
        }

        /// <summary>
        /// Used to override a portion of WndProc so we can accept key messages **/
        /// </summary>
        /// <param name="msg">Windows message</param>
        [SecurityPermission(SecurityAction.LinkDemand,Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message msg)
        {

            switch (msg.Msg)
            {
                /** We only care about hotkey messages **/
                case WM_HOTKEY:
                    /** Is it our hotkey? **/
                    if ((short)msg.WParam == kbh.HotkeyID)
                    {
                        if (Visible)
                        {
                            Hide();
                        }
                        else
                        {
                            Show();
                            BringToFront();

                            if (Properties.Settings.Default.followCursor)
                            {
                                /** chase cursor **/
                                Location = new Point(Cursor.Position.X,Cursor.Position.Y);
                            }
                            else
                            {
                                /** when set to visible, move cursor to location **/
                                Cursor.Position = PointToScreen(new Point(TxtCommand.Left,TxtCommand.Top));
                            }                       

                            TxtCommand.Focus();
                         
                        }
                    }
                    break;
                case WM_SHOW:
                    TxtCommand.Focus();
                    BringToFront();
                    base.WndProc(ref msg);
                    break;
                default:
                    /** pass it back to main WndProc **/
                    base.WndProc(ref msg);
                    break;
            }
        }

        /// <summary>
        /// Unregisters the hotkey
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            //var a = new ArrayList();

            //foreach (string item in commandHistory)
            //{
            //    a.Add(item);

            //}

            kbh.UnregisterGlobalHotKey();
            Dispose();

        }

        /// <summary>
        /// Used to apply any settings in the properties file
        /// </summary>
        private void RefreshTheme()
        {
            Properties.Settings.Default.Reload();
            TxtCommand.AutoCompleteCustomSource = commandHistory;
            TxtCommand.BackColor = Properties.Settings.Default.CommandBackcolor;
            TxtCommand.ForeColor = Properties.Settings.Default.CommandForecolor;
            TxtCommand.Font = Properties.Settings.Default.CommandFont;
            Height = TxtCommand.Height + 3;

            this.TopMost = Properties.Settings.Default.setTopmost;
            if (TopMost)
            {

                Show();
            }

        }

        /// <summary>
        /// when we dont have focus (and the form is not set to topmost) we wanna get it out of the way
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_Deactivate(object sender, EventArgs e)
        {
            if (!Properties.Settings.Default.setTopmost)
            {
                Hide();
            }

        }

        /// <summary>
        /// its pretty annoying to activate the window, then click to enter text
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_Activated(object sender, EventArgs e)
        {
            TxtCommand.Focus();
        }

        /// <summary>
        /// same cooment as FormMain_Activated
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
            {
                TxtCommand.Focus();
            }
        }

        #endregion

        /// <summary>
        /// Handles command and kotkey processing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TxtCommand_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    int success = CommandProcessor.ProcessCommand(TxtCommand.Text);

                    if (success == 1)
                    {
                        MessageBox.Show("Cannot execute command");
                    }
                    commandHistory.Add(TxtCommand.Text);
                    TxtCommand.Text = string.Empty;
                    currentIndex = commandHistory.Count;

                    if (Properties.Settings.Default.HideAfterExecute)
                    {
                        Hide();
                    }
                    break;
                case Keys.Up:
                    if ((currentIndex - 1) >= 0)
                    {
                        TxtCommand.Text = commandHistory[currentIndex - 1].ToString();
                        currentIndex--;
                    }
                    break;
                case Keys.Down:
                    if ((currentIndex + 1) < commandHistory.Count)
                    {
                        TxtCommand.Text = commandHistory[currentIndex + 1].ToString();
                        currentIndex++;
                    }
                    else
                    {
                        e.Handled = true;
                    }
                    break;
                default:
                    break;
            }

            /** can't combine keys in a case **/
            if (e.KeyCode == Keys.D && e.Modifiers == Keys.Alt)
            {
                Hide();
            }
            if (e.KeyCode == Keys.Escape && e.Modifiers == Keys.Shift)
            {
                Close();
            }

        }

        /// <summary>
        /// used to provide dragging of form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TxtCommand_MouseMove(object sender, MouseEventArgs e)
        {
            /** OR to make it both buttons **/
            if (e.Button == (MouseButtons.Right | MouseButtons.Left))
            {
                Cursor = Cursors.Arrow;
                NativeMethods.ReleaseCapture();
                NativeMethods.SendMessage(Handle, WM_NCLBUTTONDOWN, (IntPtr)HTCAPTION, (IntPtr)0);

            }
        }

        /// <summary>
        /// user clicks icon and it shows or hides...go figure
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (Visible)
            {
                Hide();
            }
            else
            {
                Show();
               
                
            }

        }

        #region Context Menu

        /// <summary>
        /// For opening Aliases dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CtxAliases_Click(object sender, EventArgs e)
        {
            var fa = new FormAlias();
            fa.ShowDialog();
        }

        /// <summary>
        /// Program options dialog
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CtxOptions_Click(object sender, EventArgs e)
        {
            var frm = new FormSettings();
            DialogResult res = frm.ShowDialog();

            if (res == DialogResult.OK)
            {
                RefreshTheme();
            }

            BringToFront();
            TxtCommand.Focus();
        }

        /// <summary>
        /// close!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CtxExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        #endregion

    }

}
